package com.leyou.auth.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.leyou.auth.ApplicationInfo;
import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.mapper.ApplicationInfoMapper;
import com.leyou.auth.pojo.AppInfo;
import com.leyou.common.auth.pojo.Payload;
import com.leyou.common.auth.pojo.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.constants.LyConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.UserClient;
import entity.User;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {
     @Autowired(required = false)
     private UserClient userClient;
     @Autowired
     private JwtProperties jwtProperties;
     @Autowired(required = false)
     private StringRedisTemplate redisTemplate;
     @Autowired(required = false)
     private ApplicationInfoMapper applicationInfoMapper;
     @Autowired
    PasswordEncoder passwordEncoder;

    public void login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
        User user = userClient.query(username, password);
        UserInfo userInfo = new UserInfo(user.getId(), user.getUsername(), "admin");

        this.generateTokenAndWriteCookie(response, userInfo);
    }

    /**
     * 生成token，并把token写出到respone中
     */
    private void generateTokenAndWriteCookie(HttpServletResponse response, UserInfo userInfo) {

        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, jwtProperties.getPrivateKey(), jwtProperties.getCookie().getExpire());
        CookieUtils.newCookieBuilder().response(response).name(jwtProperties.getCookie().getCookieName())
                                                         .value(token)
                                                         .domain(jwtProperties.getCookie().getCookieDomain())
                                                         .maxAge(jwtProperties.getCookie().getExpire()*60)
                                                         .build();
    }

    public UserInfo verify(HttpServletRequest request, HttpServletResponse response) {

        //1.从request中取出Cookie值（token）
        String cookieName = jwtProperties.getCookie().getCookieName();

        String token=null;

        if (cookieName !=null) {
           token = CookieUtils.getCookieValue(request, jwtProperties.getCookie().getCookieName());
        }

        //2.校验token是否合法
        Payload<UserInfo> payload=null;
        try {
         payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey(), UserInfo.class);
            //3.从token取出登录用户信息
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

        //判断当前token是否存在黑名单
        if (redisTemplate.hasKey(LyConstants.BACL_KEY_PRE+payload.getId())){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

        UserInfo  userinfo = payload.getInfo();
        //刷新token过期时间
        //1.取出当前token的过期时间
        Date expirationTime = payload.getExpiration();
        //2.计算刷新时间=过期时间-15
        DateTime refreshTime = new DateTime(expirationTime).minusMinutes(jwtProperties.getCookie().getRefreshTime());

        //3.判断刷新时间<当前时间，重新生成token
        //isBeforeNow(): 判断指定时间是否在当前时间之前
        if (refreshTime.isBeforeNow()){
          generateTokenAndWriteCookie(response,userinfo);
        }
          return  userinfo;
    }


    public void logout(HttpServletRequest request, HttpServletResponse response) {
        //1.取出Cookie里面的token
        String token = CookieUtils.getCookieValue(request, jwtProperties.getCookie().getCookieName());
        //2.校验token，取出载荷
        Payload<UserInfo> payload = null;
        try {
            payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey(), UserInfo.class);
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        //3. 把token加入黑名单
        addBackList(payload);
        //4.把浏览器的Cookie删除
        CookieUtils.deleteCookie(jwtProperties.getCookie().getCookieName(),jwtProperties.getCookie().getCookieDomain(),response);
    }

    public void addBackList( Payload<UserInfo> payload){
        //3.把token的id加入redis作为黑名
        String tokenId = payload.getId();
        //获取过期时间
        Date expirationTime = payload.getExpiration();
        //计算剩余有效时间
       long remainTime=   expirationTime.getTime()- System.currentTimeMillis();
        //把token的id存入redis
        redisTemplate.opsForValue().set(LyConstants.BACL_KEY_PRE+tokenId,"1",remainTime, TimeUnit.MILLISECONDS);
    }
    /**
     * 校验服务名称和服务密码是否正确
     */
    public ApplicationInfo checkServiceNamdAndSecret(String serviceName, String secret){
        //1.校验服务名是否存在
        ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.setServiceName(serviceName);
        QueryWrapper<ApplicationInfo> query = Wrappers.query(applicationInfo);
        ApplicationInfo loginAppInfo = applicationInfoMapper.selectOne(query);
        if (applicationInfo ==null){
           throw  new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }
        if (!passwordEncoder.matches(secret,loginAppInfo.getSecret())){
            throw  new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }
      return loginAppInfo;
    }

    public String  authorization(String serviceName, String secret) {
        //1.校验服务名和服务密码是否正确
        ApplicationInfo applicationInfo = checkServiceNamdAndSecret(serviceName, secret);

        //2.查询当前服务的目标服务列表
     List<String> targetList= applicationInfoMapper.findTargetListByServiceId(applicationInfo.getId());
        AppInfo appInfo = new AppInfo(applicationInfo.getId(),serviceName,targetList);
        //3.生成token，并返回token]
        String token = JwtUtils.generateTokenExpireInMinutes(appInfo, jwtProperties.getPrivateKey(), jwtProperties.getApp().getExpire());
        return token;
    }



}

